package com.wuyan.web.base.helper.jackson;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;

/**
 * 自定义LocalDateTime反序列解析器
 * 同时支持时间戳以及固定格式的日期
 * 1. yyyy-MM-dd HH:mm:ss
 * 2. yyyy-MM-dd
 * 3. 13位时间戳以及10位时间戳
 *
 * @author wuyan
 */

public class DateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
    private static final int TIMESTAMP_SECOND_LENGTH = 10;
    private static final int TIMESTAMP_MILLISECOND_LENGTH = 13;
    private static final int DATETIME_FMT_LENGTH = 19;
    private static final int DATE_FMT_LENGTH = 10;

    @Override
    public LocalDateTime deserialize(JsonParser jsonParser,
                                     DeserializationContext deserializationContext) throws IOException {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        String date = jsonParser.getValueAsString();

        if (StringUtils.isBlank(date)) {
            return null;
        }

        if (!StringUtils.isNumeric(date)) {
            if (date.trim().length() == DATETIME_FMT_LENGTH) {
                formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            } else if (date.trim().length() == DATE_FMT_LENGTH) {
                formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            }
            return LocalDateTime.parse(date, formatter);
        } else if (date.length() == TIMESTAMP_SECOND_LENGTH || date.length() == TIMESTAMP_MILLISECOND_LENGTH) {
            long timestamp = Long.parseLong(date);
            int nanoOfSecond = 0;

            if (date.length() == TIMESTAMP_MILLISECOND_LENGTH) {
                nanoOfSecond = Math.toIntExact(timestamp % 1000);
                timestamp = timestamp / 1000;
            }

            return LocalDateTime.ofEpochSecond(timestamp, nanoOfSecond, ZoneOffset.ofHours(8));
        }

        return LocalDateTime.parse(date, formatter);
    }
}